package tests;

import static org.junit.Assert.assertTrue;
import excepciones.JuegoGanadoException;
import excepciones.TrampaAlcanzadaException;
import game.model.Destino;
import game.model.Espejo;
import game.model.EspejoSimple;
import game.model.Orientable;
import game.model.Origen;
import game.model.Rayo;
import game.model.Tablero;
import game.model.Trampa;
import game.model.Vacio;

import java.awt.Color;
import java.awt.Point;

import org.junit.Before;
import org.junit.Test;

public class TableroTest {

	private Tablero tablero;
	
	/**
	 * Metodo que se corre antes de cualquier test para inicializar un tablero
	 * que sera usado en los tests posteriores.
	 * 
	 */
	
	@Before
	public void inicializa() {
		tablero = new Tablero(10,10);
		tablero.setCelda(new Point(0,0), new EspejoSimple(0));
		tablero.setCelda(new Point(9,9), new EspejoSimple(0));
		tablero.setCelda(new Point(1,0), new Origen(new Color(240,0,240), 0));
		tablero.setCelda(new Point(1,9), new Destino(new Color(240,0,240)));
		tablero.setCelda(new Point(4,7), new Trampa());
		for(int i  = 0; i < tablero.getDimensiones().x; i++) {
			for(int j  = 0; j < tablero.getDimensiones().x; j++) {
				if(tablero.getCelda(new Point(i,j)) == null) {
					tablero.setCelda(new Point(i, j), new Vacio());
				}
			}
		}
	}
	
	/**
	 * Valida si el metodo validaDimension devuelve la excepcion esperada en
	 * caso de error en los parametros.
	 * 
	 */
	
	@Test(expected = Exception.class)
	public void validaDimensionesTest() {
		new Tablero(21,10);
	}
	
	/**
	 * Valida si getCelda devuelve null en caso de parametros fuera de rango.
	 * 
	 */
	
	@Test
	public void getCeldaTest() {
		assertTrue(tablero.getCelda(new Point(5,5)) != null);
		assertTrue(tablero.getCelda(new Point(10,5)) == null);
	}
	
	/**
	 * Valida el correcto funcionamiento del metodo que mueve las piezas en el
	 * tablero del back end.
	 * 
	 */
	
	@Test
	public void moverPiezasTest() {
		assertTrue(tablero.getCelda(new Point(0,0)).getComponente() instanceof Espejo);
		assertTrue(tablero.getCelda(new Point(0,1)).getComponente() instanceof Vacio);
		tablero.MoverPiezas(0,0,0,1);
		assertTrue(tablero.getCelda(new Point(0,1)).getComponente() instanceof Espejo);
		assertTrue(tablero.getCelda(new Point(0,0)).getComponente() instanceof Vacio);
	}
	
	/**
	 * Valida el correcto funcionamiento del metodo que rota las piezas en el
	 * tablero del back end.
	 * 
	 */
	
	@Test
	public void rotarPiezaTest() {
		assertTrue(((Orientable)tablero.getCelda(new Point(9,9)).getComponente()).getOrientacion() == 0);
		((Orientable)tablero.getCelda(new Point(9,9)).getComponente()).rotar();
		assertTrue(((Orientable)tablero.getCelda(new Point(9,9)).getComponente()).getOrientacion() == 1);
	}
	
	/**
	 * Valida que la suma de puntos valga lo esperado en funcion del tablero
	 * que se tiene al momento de terminar el nivel.
	 * 
	 */
	
	@Test
	public void totalPuntosTest() {
		Origen origen = (Origen)tablero.getCelda(new Point(1,0)).getComponente();
		Rayo inicial = new Rayo(origen.getColor(), origen.getOrientacion());
		tablero.dibujar(new Point(1,0), inicial);
		assertTrue(tablero.totalPuntos() == 10);
	}
	
	/**
	 * Valida que la excepcion de nivel ganado se lance en el momento adecuado.
	 * 
	 */
	
	@Test(expected = JuegoGanadoException.class)
	public void verificaFinTest1() {
		Origen origen = (Origen)tablero.getCelda(new Point(1,0)).getComponente();
		Rayo inicial = new Rayo(origen.getColor(), origen.getOrientacion());
		tablero.dibujar(new Point(1,0), inicial);
		tablero.verificaFin();
	}
	
	/**
	 * Valida que la excepcion de trampa alcanzada se lance en el momento adecuado.
	 * 
	 */
	
	@Test(expected = TrampaAlcanzadaException.class)
	public void verificaFinTest2() {
		tablero.MoverPiezas(0,0,1,7);
		Origen origen = (Origen)tablero.getCelda(new Point(1,0)).getComponente();
		Rayo inicial = new Rayo(origen.getColor(), origen.getOrientacion());
		tablero.dibujar(new Point(1,0), inicial);
		tablero.verificaFin();
	}
	
}
